home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / sound / mpdecode / mpdecode.c < prev    next >
C/C++ Source or Header  |  1999-11-29  |  9KB  |  414 lines

  1.  
  2. #define TEMPLATE "Names/M,OutDir/K"
  3. #define BUFFERS 64
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <math.h>
  9.  
  10. #include <proto/exec.h>
  11. #include <proto/dos.h>
  12. #include <proto/mpega.h>
  13.  
  14. #include <exec/memory.h>
  15.  
  16. char Version[]="\0$VER: mpdecode 1.0 (30.10.99) by Thomas Wenzel\0";
  17.  
  18. struct Library    *MPEGABase;
  19.  
  20. MPEGA_CTRL        mctrl;
  21. MPEGA_STREAM      *mstream;
  22.  
  23. struct RDArgs     *rdargs;
  24. struct AnchorPath *APath;
  25. char              *CurrentName;
  26. ULONG             NameCount;
  27. ULONG             Signals;
  28.  
  29. WORD              *Buffer[MPEGA_MAX_CHANNELS];
  30. WORD              *OutBuffer;
  31.  
  32. char              OutDir[1024];
  33.  
  34. struct { /* Args structure */
  35.     char    **Names;
  36.     char    *OutDir;
  37. } Args = {
  38.     NULL,
  39.     NULL
  40. };
  41.  
  42. struct {
  43.     ULONG    FORMid;
  44.     ULONG    FORMsize;
  45.     ULONG    AIFFid;
  46.  
  47.   ULONG    FVERid;
  48.   ULONG    FVERsize;
  49.   ULONG    FVERtime;
  50.  
  51.     ULONG    COMMid;
  52.     ULONG    COMMsize;
  53.  
  54.     UWORD    nTracks;
  55.     ULONG    nFrames;
  56.     UWORD    bpSmpl;
  57.     char    freq[10];
  58.     ULONG    compType;
  59.     char    compressionName[(sizeof("not compressed")+1)&(~1)];
  60.  
  61.     ULONG    SSNDid;
  62.     ULONG    SSNDsize;
  63.     ULONG    offset;
  64.     ULONG    blockSize;
  65. } AIFFheader = {
  66.     0x464F524D, // FORM
  67.     NULL,
  68.     0x41494643, // AIFC
  69.  
  70.     0x46564552, // FVER
  71.     4,
  72.     0xA2805140, // file format version #1
  73.  
  74.     0x434F4D4D, // COMM
  75.     38,
  76.     2,
  77.     0,
  78.     16,
  79.     0,0,0,0,0,0,0,0,0,0,
  80.     0x4E4F4E45, // NONE
  81.     sizeof("not compressed")-1,'n','o','t',' ','c','o','m','p','r','e','s','s','e','d',0,
  82.     0x53534E44,
  83.     0,
  84.     0,
  85.     0
  86. };
  87.  
  88.  
  89. BOOL Init(void);
  90. void Free(void);
  91. void Decode(char *Name);
  92. void ConvertToIeeeExtended(double, char *);
  93.  
  94. int main(int argc, char **argv) {
  95.     char c;
  96.  
  97.     printf("\n");
  98.     printf("mpdecode 1.0 by Thomas Wenzel\n");
  99.     printf("-----------------------------\n");
  100.     printf("This program decodes multiple MPEG audio files to AIFF-C.\n");
  101.     printf("Freeware. Provided 'as is'. For non-commercial use only.\n");
  102.     printf("\n");
  103.  
  104.     if(!Init()) {
  105.         Free();
  106.         return(10);
  107.     }
  108.  
  109.     if((rdargs = ReadArgs(TEMPLATE, (LONG *)&Args, NULL)) == NULL) {
  110.         PrintFault(IoErr(), "mpdecode");
  111.         Free();
  112.         return(10);
  113.     }
  114.  
  115.     if(!Args.Names) {
  116.         printf("Usage: mpdecode %s\n", TEMPLATE);
  117.         Free();
  118.         return(5);
  119.     }
  120.  
  121.     if(Args.OutDir) {
  122.         strcpy(OutDir, Args.OutDir);
  123.         c=OutDir[strlen(OutDir)-1];
  124.         if((c != ':') && (c != '/')) strcat(OutDir, "/");
  125.     }
  126.     else {
  127.         OutDir[0]=0;
  128.     }
  129.  
  130.     NameCount=0;
  131.     while(Args.Names[NameCount]!=NULL) {
  132.         CurrentName=Args.Names[NameCount];
  133.         if(MatchFirst(CurrentName,APath)==0) {
  134.             do {
  135.                 Signals=CheckSignal(SIGBREAKF_CTRL_C);
  136.                 if(Signals) break;
  137.                 Decode(APath->ap_Buf);
  138.             } while (MatchNext(APath)==0);
  139.             MatchEnd(APath);
  140.             if(Signals) break;
  141.         }
  142.         NameCount++;
  143.     }
  144.  
  145.     if(Signals) printf("mpdecode: BREAK\n");
  146.     Free();
  147.     return(0);
  148. }
  149.  
  150. BOOL Init(void) {
  151.     ULONG i;
  152.  
  153.     MPEGABase=OpenLibrary("mpega.library", 2);
  154.     if(!MPEGABase) {
  155.         printf("Can't open mpega.library v2\n");
  156.         return(FALSE);
  157.     }
  158.     APath=AllocVec(sizeof(*APath)+256, MEMF_PUBLIC|MEMF_CLEAR);
  159.     if(!APath) {
  160.         printf("Out of memory!\n");
  161.         return(FALSE);
  162.     }
  163.     APath->ap_Strlen=255;
  164.  
  165.     for(i=0; i<MPEGA_MAX_CHANNELS; i++) {
  166.         Buffer[i]=AllocVec(BUFFERS*MPEGA_PCM_SIZE*sizeof(WORD), MEMF_PUBLIC|MEMF_CLEAR);
  167.         if(!Buffer[i]) {
  168.             printf("Out of memory!\n");
  169.             return(FALSE);
  170.         }
  171.     }
  172.  
  173.     OutBuffer=AllocVec(BUFFERS*MPEGA_PCM_SIZE*sizeof(WORD)*2, MEMF_PUBLIC|MEMF_CLEAR);
  174.     if(!OutBuffer) {
  175.         printf("Out of memory!\n");
  176.         return(FALSE);
  177.     }
  178.  
  179.     mctrl.bs_access                 = NULL;
  180.     mctrl.layer_1_2.force_mono      = 0;
  181.     mctrl.layer_1_2.mono.freq_div   = 1;
  182.     mctrl.layer_1_2.mono.quality    = 2;
  183.     mctrl.layer_1_2.mono.freq_max   = 48000;
  184.     mctrl.layer_1_2.stereo.freq_div = 1;
  185.     mctrl.layer_1_2.stereo.quality  = 2;
  186.     mctrl.layer_1_2.stereo.freq_max = 48000;
  187.     mctrl.layer_3.force_mono        = 0;
  188.     mctrl.layer_3.mono.freq_div     = 1;
  189.     mctrl.layer_3.mono.quality      = 2;
  190.     mctrl.layer_3.mono.freq_max     = 48000;
  191.     mctrl.layer_3.stereo.freq_div   = 1;
  192.     mctrl.layer_3.stereo.quality    = 2;
  193.     mctrl.layer_3.stereo.freq_max   = 48000;
  194.     mctrl.check_mpeg                = 1;
  195.     mctrl.stream_buffer_size        = 0;
  196. }
  197.  
  198. void Free(void) {
  199.     ULONG i;
  200.  
  201.     for(i=0; i<MPEGA_MAX_CHANNELS; i++) {
  202.         if(Buffer[i]) FreeVec(Buffer[i]);
  203.     }
  204.     if(OutBuffer) FreeVec(OutBuffer);
  205.  
  206.     if(rdargs)    FreeArgs(rdargs);
  207.     if(APath)     FreeVec(APath);
  208.     if(MPEGABase) CloseLibrary(MPEGABase);
  209. }
  210.  
  211. void Decode(char *Name) {
  212.     ULONG i,j,ptr;
  213.     FILE *OutFile;
  214.     char OutFileName[1024];
  215.  
  216.     ULONG BadFrames;
  217.     LONG Count;
  218.     ULONG SamplesInFile;
  219.     ULONG SamplesInBuf;
  220.     ULONG BytesWritten;
  221.     ULONG Length, Time;
  222.     BOOL WriteError;
  223.     BOOL eof;
  224.  
  225.     WriteError=FALSE;
  226.     eof=FALSE;
  227.  
  228.     if(OutDir[0]) {
  229.         sprintf(OutFileName, "%s%s.aiff", OutDir, FilePart(Name));
  230.     }
  231.     else {
  232.         sprintf(OutFileName, "%s.aiff", Name);
  233.     }
  234.  
  235.     printf("\nFilename: %s -> %s\n", Name, OutFileName);
  236.     mstream=MPEGA_open(Name, &mctrl);
  237.     if(!mstream) {
  238.         printf("Can't open input file!\n");
  239.         return;
  240.     }
  241.  
  242.     OutFile=fopen(OutFileName, "wb");
  243.     if(!OutFile) {
  244.         printf("Can't open output file!\n");
  245.         MPEGA_close(mstream);
  246.         return;    
  247.     }
  248.  
  249.     if(fwrite(&AIFFheader, sizeof(AIFFheader), 1, OutFile) != 1) WriteError=TRUE;
  250.  
  251.     Length=mstream->ms_duration/1000;
  252.  
  253.     SamplesInFile=0;
  254.     BadFrames=0;
  255.  
  256.     while(!eof) {
  257.         if(MPEGA_time(mstream, &Time)==0) {
  258.             printf("Decoding: %ds/%ds (%d%%)", Time/1000, Length, Time/Length/10);
  259.             if(BadFrames) printf(" [%d bad frames]", BadFrames);
  260.             printf("\r");
  261.         }
  262.         flushall();
  263.  
  264.         ptr=0;
  265.         SamplesInBuf=0;
  266.         for(i=0; i<BUFFERS; i++) {
  267.             Signals=CheckSignal(SIGBREAKF_CTRL_C);
  268.             if(Signals || WriteError) break;
  269.             Count=MPEGA_decode_frame(mstream, Buffer);
  270.  
  271.             if(Count==MPEGA_ERR_BADFRAME) BadFrames++;
  272.  
  273.             if(Count < 0) {
  274.                 if(Count==MPEGA_ERR_EOF) {
  275.                     eof=TRUE;
  276.                 }
  277.                 else {
  278.                     Count=0;
  279.                 }
  280.             }
  281.  
  282.             if(Count>BUFFERS*MPEGA_PCM_SIZE) Count=BUFFERS*MPEGA_PCM_SIZE;
  283.  
  284.             if(Count>0) {
  285.                 switch(mstream->channels) {
  286.                     case 1:
  287.                         for(j=0; j<Count; j++) {
  288.                             OutBuffer[ptr++] = Buffer[0][j];
  289.                         }
  290.                     break;
  291.                     case 2:
  292.                         for(j=0; j<Count; j++) {
  293.                             OutBuffer[ptr++] = Buffer[0][j];
  294.                             OutBuffer[ptr++] = Buffer[1][j];
  295.                         }
  296.                     break;
  297.                 }
  298.             }
  299.             SamplesInBuf += Count;
  300.         }
  301.  
  302.         if(Signals || WriteError) break;
  303.  
  304.         if(SamplesInBuf) {
  305.             if(fwrite(OutBuffer, SamplesInBuf, 2*mstream->channels, OutFile) != 2*mstream->channels) WriteError=TRUE;
  306.             SamplesInFile += SamplesInBuf;
  307.         }
  308.     }
  309.  
  310.     BytesWritten=SamplesInFile*2*mstream->channels;
  311.  
  312.     AIFFheader.bpSmpl   = 16;
  313.     AIFFheader.nFrames  = SamplesInFile;
  314.     AIFFheader.SSNDsize = BytesWritten +4+4; // +4+4: offset and blockSize
  315.     ConvertToIeeeExtended((double)mstream->frequency, AIFFheader.freq);
  316.     AIFFheader.nTracks  = mstream->channels;
  317.     AIFFheader.FORMsize = BytesWritten+70 +4+4; // +4+4: offset and blockSize
  318.  
  319.     fseek(OutFile, 0, SEEK_SET);
  320.     fwrite(&AIFFheader, sizeof(AIFFheader), 1, OutFile);
  321.  
  322.     MPEGA_close(mstream);
  323.     fclose(OutFile);
  324.     if(WriteError) printf("\nCan't write to output file!\n");
  325.     if(Signals || WriteError) printf("\n");
  326.     else                      printf("Decoding: %ds/%ds (%d%%)\n", Length, Length, 100);
  327. }
  328.  
  329.  
  330. /*
  331.  * C O N V E R T   T O   I E E E   E X T E N D E D
  332.  */
  333.  
  334. /* Copyright (C) 1988-1991 Apple Computer, Inc.
  335.  * All rights reserved.
  336.  *
  337.  * Machine-independent I/O routines for IEEE floating-point numbers.
  338.  *
  339.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  340.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  341.  * impossible to preserve NaN's in a machine-independent way.
  342.  * Infinities are, however, preserved on IEEE machines.
  343.  *
  344.  * These routines have been tested on the following machines:
  345.  *    Apple Macintosh, MPW 3.1 C compiler
  346.  *    Apple Macintosh, THINK C compiler
  347.  *    Silicon Graphics IRIS, MIPS compiler
  348.  *    Cray X/MP and Y/MP
  349.  *    Digital Equipment VAX
  350.  *
  351.  *
  352.  * Implemented by Malcolm Slaney and Ken Turkowski.
  353.  *
  354.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  355.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  356.  * floating-point format, and conversions to and from IEEE single-
  357.  * precision floating-point format.
  358.  *
  359.  * In 1991, Ken Turkowski implemented the conversions to and from
  360.  * IEEE double-precision format, added more precision to the extended
  361.  * conversions, and accommodated conversions involving +/- infinity,
  362.  * NaN's, and denormalized numbers.
  363.  */
  364.  
  365.  
  366. # define FloatToUnsigned(f)      ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L) + 1)
  367.  
  368. void ConvertToIeeeExtended(double num, char *bytes) {
  369.     int            sign;
  370.     int            expon;
  371.     double    fMant, fsMant;
  372.     ULONG        hiMant, loMant;
  373.  
  374.     if (num < 0) {
  375.         sign = 0x8000;
  376.         num *= -1;
  377.     }
  378.     else sign = 0;
  379.  
  380.     if (num == 0) {
  381.         expon = 0; hiMant = 0; loMant = 0;
  382.     }
  383.     else {
  384.         fMant = frexp(num, &expon);
  385.         if ((expon > 16384) || !(fMant < 1)) {    /* Infinity or NaN */
  386.             expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
  387.         }
  388.         else {    /* Finite */
  389.             expon += 16382;
  390.             if (expon < 0) {    /* denormalized */
  391.                 fMant = ldexp(fMant, expon);
  392.                 expon = 0;
  393.             }
  394.             expon |= sign;
  395.             fMant = ldexp(fMant, 32);          
  396.             fsMant = floor(fMant); 
  397.             hiMant = FloatToUnsigned(fsMant);
  398.             fMant = ldexp(fMant - fsMant, 32); 
  399.             fsMant = floor(fMant); 
  400.             loMant = FloatToUnsigned(fsMant);
  401.         }
  402.     }
  403.     bytes[0] = expon >> 8;
  404.     bytes[1] = expon;
  405.     bytes[2] = hiMant >> 24;
  406.     bytes[3] = hiMant >> 16;
  407.     bytes[4] = hiMant >> 8;
  408.     bytes[5] = hiMant;
  409.     bytes[6] = loMant >> 24;
  410.     bytes[7] = loMant >> 16;
  411.     bytes[8] = loMant >> 8;
  412.     bytes[9] = loMant;
  413. }
  414.